//
//  HLENetWorkCache.m
//  HLENetwork_Example
//
//  Created by hle1879 on 2020/9/28.
//  Copyright © 2020 13434436448@163.com. All rights reserved.
//

#import "HLENetWorkCache.h"
#import <YYCache/YYCache.h>
#import "HLEConst.h"
#import "HLEBaseRequest.h"
#import "HLENetWorkConfig.h"

static NSString *const HLECacheValidTime = @"HLECacheValidTime";

@implementation HLENetWorkCache
static YYCache *_dataCache;
static HLENetWorkConfig *_config;

+(void)initialize{
    _config = [HLENetWorkConfig defaultConfig];
    _dataCache = [YYCache cacheWithPath:_config.cachePath];
}

+ (void)initWithCachePath:(NSString *)cachePath{
    _config = [HLENetWorkConfig defaultConfig];
    _dataCache = [YYCache cacheWithPath:cachePath];
}

+ (void)initWithConfig:(HLENetWorkConfig*)config{
    _config = config;
    _dataCache = [YYCache cacheWithPath:config.cachePath];
}

+ (void)setCacheWithRequest:(HLEBaseRequest*)request cacheData:(id _Nullable)cacheData validTime:(NSTimeInterval)validTime{
    NSString *cacheKey = [self cacheKeyWithURL:request.url parameters:[self filterNeedlessParams:request.params]];
    [self setCacheWithCacheKey:cacheKey cacheData:cacheData validTime:validTime];
}

+ (void)setCacheWithRequest:(HLEBaseRequest*)request cacheData:(id _Nullable)cacheData validTime:(NSTimeInterval)validTime completion:(void(^)(void))completion{
    NSString *cacheKey = [self cacheKeyWithURL:request.url parameters:[self filterNeedlessParams:request.params]];
    [self setCacheWithCacheKey:cacheKey cacheData:cacheData validTime:validTime completion:completion];
}


+ (void)setCacheWithCacheKey:(NSString*)cacheKey cacheData:(id _Nullable)cacheData validTime:(NSTimeInterval)validTime{
    [_dataCache setObject:cacheData forKey:cacheKey];
    if (validTime != CacheValidTimeForever) {
        [self setCacheValidTimeWithCacheKey:cacheKey];
    }
}

+ (void)setCacheWithCacheKey:(NSString*)cacheKey cacheData:(id _Nullable)cacheData validTime:(NSTimeInterval)validTime completion:(void(^)(void))completion{
    [_dataCache setObject:cacheData forKey:cacheKey withBlock:^{
        completion ? completion() : nil;
    }];
    if (validTime != CacheValidTimeForever) {
        [self setCacheValidTimeWithCacheKey:cacheKey];
    }
}


+ (id)getCacheWithRequest:(HLEBaseRequest*)request validTime:(NSTimeInterval)validTime{
    NSString *cacheKey = [self cacheKeyWithURL:request.url parameters:[self filterNeedlessParams:request.params]];
    return [self getCacheWithCacheKey:cacheKey validTime:validTime];
}

+ (void)getCacheWithRequest:(HLEBaseRequest*)request validTime:(NSTimeInterval)validTime completion:(void(^)(NSString * _Nonnull, id<NSCoding>  _Nullable))completion{
    NSString *cacheKey = [self cacheKeyWithURL:request.url parameters:[self filterNeedlessParams:request.params]];
    [self getCacheWithCacheKey:cacheKey validTime:validTime completion:completion];
}

+ (id)getCacheWithCacheKey:(NSString*)cacheKey validTime:(NSTimeInterval)validTime{
    id data = [_dataCache objectForKey:cacheKey];
    if (!data) {
        return nil;
    }
    if (validTime != CacheValidTimeForever) {
        if ([self verifyCacheValidWithCacheKey:cacheKey validTime:validTime]) {
            return data;
        }else {
            [_dataCache removeObjectForKey:cacheKey];
            NSString *cacheValidTimeKey = [NSString stringWithFormat:@"%@_%@",cacheKey, HLECacheValidTime];
            [_dataCache removeObjectForKey:cacheValidTimeKey];
            return nil;
        }
    }
    return data;
}


+ (void)getCacheWithCacheKey:(NSString*)cacheKey validTime:(NSTimeInterval)validTime completion:(void(^)(NSString * _Nonnull, id<NSCoding>  _Nullable))completion{
    if (validTime != CacheValidTimeForever) {
        if ([self verifyCacheValidWithCacheKey:cacheKey validTime:validTime]) {
            [_dataCache objectForKey:cacheKey withBlock:^(NSString * _Nonnull key, id<NSCoding>  _Nonnull object) {
                completion ? completion(key,object) : nil;
            }];
        }else {
            [_dataCache removeObjectForKey:cacheKey];
            NSString *cacheValidTimeKey = [NSString stringWithFormat:@"%@_%@",cacheKey, HLECacheValidTime];
            [_dataCache removeObjectForKey:cacheValidTimeKey];
        }
    }else{
        [_dataCache objectForKey:cacheKey withBlock:^(NSString * _Nonnull key, id<NSCoding>  _Nonnull object) {
            completion ? completion(key,object) : nil;
        }];
    }
}

+ (void)removeCacheWithRequest:(HLEBaseRequest*)request{
    NSString *cacheKey = [self cacheKeyWithURL:request.url parameters:[self filterNeedlessParams:request.params]];
    [self removeCacheWithCacheKey:cacheKey];
}


+ (void)removeCacheWithRequest:(HLEBaseRequest*)request completion:(void(^)(NSString * _Nonnull))completion{
    NSString *cacheKey = [self cacheKeyWithURL:request.url parameters:[self filterNeedlessParams:request.params]];
    [self removeCacheWithCacheKey:cacheKey completion:completion];
}

+ (void)removeCacheWithCacheKey:(NSString*)cacheKey{
    [_dataCache removeObjectForKey:cacheKey];
}

+ (void)removeCacheWithCacheKey:(NSString*)cacheKey completion:(void(^)(NSString * _Nonnull))completion{
    [_dataCache removeObjectForKey:cacheKey withBlock:^(NSString * _Nonnull key) {
        completion ? completion(key) : nil;
    }];
}

+ (void)removeAllCache{
    [_dataCache removeAllObjects];
}

+ (void)removeAllCacheWithCompletion:(void(^)(void))completion{
    [_dataCache removeAllObjectsWithBlock:^{
        completion ? completion() : nil;
    }];
}

+ (NSUInteger)totalCacheSize{
    return [_dataCache.diskCache totalCost];
}

+ (NSString *)totalCacheSizeDescription{
    NSInteger cacheSize = [_dataCache.diskCache totalCost];
    if (cacheSize < 1024) {
        return [NSString stringWithFormat:@"%ldB",(long)cacheSize];
    } else if (cacheSize < powf(1024.f, 2)) {
        return [NSString stringWithFormat:@"%.2fKB",cacheSize / 1024.f];
    } else if (cacheSize < powf(1024.f, 3)) {
        return [NSString stringWithFormat:@"%.2fMB",cacheSize / powf(1024.f, 2)];
    } else {
        return [NSString stringWithFormat:@"%.2fGB",cacheSize / powf(1024.f, 3)];
    }
}

#pragma mark - 缓存参数拼接处理
+ (NSString *)cacheKeyWithURL:(NSString *)url parameters:(NSDictionary *)parameters {
    if(!parameters || parameters.count == 0) {
        return url;
    }
    NSData *stringData = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:nil];
    NSString *paramsString = [[NSString alloc] initWithData:stringData encoding:NSUTF8StringEncoding];
    NSString *cacheKey = [NSString stringWithFormat:@"%@%@",url,paramsString];
    return [NSString stringWithFormat:@"%@",cacheKey];
}

#pragma mark - 参数过滤
+ (NSDictionary *)filterNeedlessParams:(NSDictionary *)params {
    NSMutableDictionary *filterParams = [NSMutableDictionary dictionaryWithDictionary:params];
    if (_config.cacheNeedlessParamsForKeys && _config.cacheNeedlessParamsForKeys > 0) {
        [filterParams removeObjectsForKeys:_config.cacheNeedlessParamsForKeys];
    }
    return filterParams.copy;
}

#pragma mark - 设置缓存的有效期
+ (void)setCacheValidTimeWithCacheKey:(NSString *)cacheKey {
    NSString *cacheValidTimeKey = [NSString stringWithFormat:@"%@_%@",cacheKey, HLECacheValidTime];
    NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
    [_dataCache setObject:@(currentTime) forKey:cacheValidTimeKey];
}

#pragma mark - 判断缓存有效
+ (BOOL)verifyCacheValidWithCacheKey:(NSString *)cacheKey validTime:(NSTimeInterval)validTime {
    NSString *cacheValidTimeKey = [NSString stringWithFormat:@"%@_%@",cacheKey, HLECacheValidTime];
    id createRecordTime = [_dataCache objectForKey:cacheValidTimeKey];
    NSTimeInterval createTime = [createRecordTime doubleValue];
    NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
    if ((currentTime - createTime) < validTime) {
        return YES;
    }
    return NO;
}
@end
